#pragma once


#include <brpc/channel.h>
#include <string>
#include <unordered_map>
#include <vector>
#include <memory>
#include <mutex>
#include "./../../../common/log.hpp"


// 封装单个服务的信道管理
class ServiceChennel
{
public:
    using ChannelPtr = std::shared_ptr<brpc::Channel>;
    
    ServiceChennel(const std::string& service_name)
        : _service_name(service_name)
        , _index(0)
    {
        
    }

    // 服务上线了一个节点 又有主机要使用我们的服务  append增加信道
    void append(const std::string& host_name)
    {
        // 创建信道
        brpc::ChannelOptions options;
        options.connect_timeout_ms = -1;
        options.timeout_ms = -1;
        options.max_retry - 3;
        options.protocol = "baidu_std";

        auto channel = std::make_shared<brpc::Channel>();
        int ret = channel->Init(host_name.c_str(), &options);
        if(ret == -1)
        {
            ERROR_LOG("信道创建失败");
            return;
        }
        
        // 加锁
        std::unique_lock<std::mutex> lock(_mutex);

        _host.insert({ host_name, channel });
        _channels.push_back(channel);
    }

    // 服务下线了一个节点 有个主机下线了  remove对应的信道节点
    void remove(const std::string& host_name)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if(_host.count(host_name) == 0)
        {
            ERROR_LOG("remove err 主机号不存在");
            return;
        }
        auto channelptr = _host[host_name];
        for(auto it = _channels.begin(); it != _channels.end(); ++it)
        {
            if(*it == channelptr)
            {
                _channels.erase(it);
                break;
            }
        }
        
        _host.erase(host_name);
    }

    ChannelPtr choose()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if(_channels.size() == 0)
        {
            ERROR_LOG("当前没有能提供{}服务的节点", _service_name);
            return ChannelPtr();
        }
        int pos = _index++ % _channels.size();

        return _channels[pos];
    }

private:
    int _index = 0;                      // 轮转下标计数器
    std::mutex _mutex;
    std::string _service_name;           // 服务名
    std::vector<ChannelPtr> _channels;    // 一个服务对应的多个信道
    std::unordered_map<std::string, ChannelPtr> _host; //主机名 对于  信道
};


// 总体服务信道管理类
class ServiceManager
{
public:
    using ServicePtr = std::shared_ptr<ServiceChennel>;
    
    // 获取一个服务的信道节点
    ServiceChennel::ChannelPtr choose(const std::string& service_name)
    {
        std::unique_lock<std::mutex> lock(_mutex);

        
        if(_services.count(service_name) == 0)
        {
            ERROR_LOG("当前没有提供{}服务的节点", service_name);
            return ServiceChennel::ChannelPtr();
        }

        return _services[service_name]->choose();
    }

    // 关注哪些上下线服务
    void declared(const std::string& service_name)
    {
        std::unique_lock<std::mutex> lock(_mutex);

        _follow_service.insert(service_name);
        DEBUG_LOG("关注服务{}成功", service_name);
    }

    // 服务上线时的回调接口 将服务节点管理起来
    void Online(const std::string& service_instance, const std::string& host_name)
    {
        const std::string& service_name = getServiceName(service_instance);
        ServicePtr service;
        {
            std::unique_lock<std::mutex> lock(_mutex);


            // 是否关注该服务
            if(_follow_service.count(service_name) == 0)
            {
                DEBUG_LOG("{}服务上线 但当前不关心", service_name)
                return;
            }

            // 获取管理对象 没有创建
            if(_services.count(service_name) == 0)
            {
                service = std::make_shared<ServiceChennel>(host_name);
                _services.insert({ service_name, service });
            }
            else 
            {
                service = _services[service_name];
            }
        }
        
        if(service == nullptr)
        {
            ERROR_LOG("添加服务节点{}失败", service_name);
            return;
        }

        service->append(host_name);
        
    }
    
    // 服务下线时的回调接口 从服务信道管理中 删除指定节点
    void Offline(const std::string& service_instance, const std::string& host_name)
    {
        const std::string& service_name = getServiceName(service_instance);

        ServicePtr service;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            
            // 是否关注该服务
            if(_follow_service.count(service_name) == 0)
            {
                DEBUG_LOG("{}服务下线 但当前不关心", service_name)
                return;
            }

            if(_services.count(service_name) == 0)
            {
                WARN_LOG("删除{}节点服务时， 没有找到管理对象", service_name);
                return;
            }
            service = _services[service_name];
        }
        
        service->remove(host_name);
    }

private:
    std::string getServiceName(const std::string& name)
    {
        int pos = name.rfind('/');
        return name.substr(0, pos);
    }

private:
    std::mutex _mutex;
    std::unordered_set<std::string> _follow_service;          // 是否关心该服务
    std::unordered_map<std::string, ServicePtr> _services;  // 服务名称 <-> 服务
};